﻿using CTM.Web.Filters;
using CTM.Web.Models.Input;
using CTM.Web.Models.View.Feedback;
using CTM.Web.Services;
using CTM.Web.Utils;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace CTM.Web.Controllers
{
    public class FeedbackController : Controller
    {
        private IPostService feedbackService;
        private IAccountService accountService;
        private ICategoryService categoryService;        
        private ITagService tagService;
        private INotificationService notificationService;
        private ICommentService commentService;
        private ApplicationUserManager userManager;

        public ApplicationUserManager UserManager
        {
            get
            {
                return userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                userManager = value;
            }
        }

        public FeedbackController(IPostService feedbackService, IAccountService accountService, ICategoryService categoryService,
            ITagService tagService, INotificationService notificationService, ICommentService commentService)
        {
            this.feedbackService = feedbackService;
            this.accountService = accountService;
            this.categoryService = categoryService;
            this.tagService = tagService;
            this.notificationService = notificationService;
            this.commentService = commentService;
        }

        [ApplicationAuthorize(Permissions = Rights.View + Modules.Conversation)]
        public ActionResult Index(string id, FeedbackSearchModel searchModel)
        {
            // Delete the notification
            if (!string.IsNullOrEmpty(Request.QueryString["notification"]))
            {
                var notification = notificationService.GetById(Request.QueryString["notification"]);
                notification.IsDeleted = true;
                notificationService.Update(notification);

                Request.QueryString.Remove("notification");
            }

            id = string.IsNullOrEmpty(id) ? GlobalVariables.CurrentUser.Id : id;
            searchModel.Id = id;
            GlobalVariables.SelectedUser = accountService.GetById(id);

            if (Request.QueryString.Count == 0)
            {
                searchModel.Emoticons = Enum.GetValues(typeof(Emoticon)).Cast<Emoticon>().ToList();
            }

            // Retrieve feedbacks from DB
            var feedbacks = feedbackService.SearchFeedbacks(UserManager, searchModel).Where(f => f.Employee.Id == id);
            searchModel.Feedbacks = feedbacks.OrderByDescending(f => f.CreatedOn);

            return View(searchModel);
        }

        public ActionResult FeedbackContentPartial(Guid? id)
        {
            if (!id.HasValue) return PartialView(new FeedbackViewModel());

            var feedback = feedbackService.GetById(id);

            if (feedback.IsDeleted) return Json(false, JsonRequestBehavior.AllowGet);

            if (GlobalVariables.CurrentUser.Id != GlobalVariables.SelectedUser.Id && !ApplicationHelpers.IsManager(accountService, UserManager, GlobalVariables.CurrentUser.Id, GlobalVariables.SelectedUser.Id)
                && feedback.IsPrivate && GlobalVariables.CurrentUser.Id != feedback.Manager.Id)
            {
                return Json(false, JsonRequestBehavior.AllowGet);
            }

            return PartialView("_FeedbackContent", new FeedbackViewModel(feedback));
        }

        [ApplicationAuthorize(Permissions = Rights.Create + Modules.Conversation)]
        public ActionResult Create()
        {
            ViewBag.IsManager = ApplicationHelpers.IsManager(accountService, UserManager, GlobalVariables.CurrentUser.Id, GlobalVariables.SelectedUser.Id);
            if (Request.IsAjaxRequest())
                return PartialView();
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        [ApplicationAuthorize(Permissions = Rights.Create + Modules.Conversation)]
        public ActionResult Create(FeedbackUpdateModel createModel)
        {
            // Clear some validations since they're not necessary
            ModelState.Remove("Id");
            ModelState.Remove("Category");
            ModelState.Remove("Tags");

            if (ModelState.IsValid)
            {
                // The Giver will be represented as Post.Manager
                var giver = accountService.GetById(GlobalVariables.CurrentUser.Id);
                // The Receiver will be represented as Post.Employee
                var receiver = accountService.GetById(GlobalVariables.SelectedUser.Id);

                #region Create feedback

                var feedback = new Post
                {
                    Id = Guid.NewGuid(),
                    Category = categoryService.GetByName("Feedback"),
                    CreatedBy = GlobalVariables.CurrentUser.Id,
                    Title = "Feedback",
                    Description = createModel.Description,
                    Emoticon = createModel.Emoticon,
                    IsPrivate = createModel.IsPrivate,
                    Manager = giver,
                    Employee = receiver,
                };

                var tags = Request.Form["Tags"].Split(',');
                for (int i = 0; i < tags.Length; i++)
                {
                    if (string.IsNullOrWhiteSpace(tags[i])) continue;

                    string tagName = tags[i];
                    var tag = tagService.GetByName(tagName);
                    if (tag != null)
                    {
                        if (!feedback.Tags.Contains(tag))
                        {
                            feedback.Tags.Add(tag);
                        }
                    }
                    else
                    {
                        tag = new Tag
                        {
                            Name = tagName
                        };
                        tagService.Insert(tag);
                        feedback.Tags.Add(tag);
                    }
                }

                feedbackService.Insert(feedback);

                #endregion

                #region Create notification

                notificationService.Create(feedback, GlobalVariables.CurrentUser.Id);

                #endregion
            }

            var result = new
            {
                success = ModelState.IsValid,
                message = string.Join("\n", ModelState.SelectMany(s => s.Value.Errors).Select(e => e.ErrorMessage))
            };
            return Json(result);
        }

        [ApplicationAuthorize(Permissions = Rights.Modify + Modules.Conversation)]
        public ActionResult Edit(Guid? id)
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        [ApplicationAuthorize(Permissions = Rights.Modify + Modules.Conversation)]
        public ActionResult Edit(FeedbackUpdateModel editModel)
        {
            // Clear some validations since they're not necessary
            ModelState.Remove("Category");
            ModelState.Remove("Tags");

            if (ModelState.IsValid)
            {
                #region Edit feedback

                var feedback = feedbackService.GetById(editModel.Id);
                feedback.Description = editModel.Description;
                feedback.Emoticon = editModel.Emoticon;
                feedback.IsPrivate = editModel.IsPrivate;
                feedback.ModifiedBy = GlobalVariables.CurrentUser.Id;
                feedback.ModifiedOn = DateTime.UtcNow;

                feedback.Tags.Clear();
                var tags = Request.Form["Tags"].Split(',');
                for (int i = 0; i < tags.Length; i++)
                {
                    if (string.IsNullOrWhiteSpace(tags[i])) continue;

                    string tagName = tags[i];
                    var tag = tagService.GetByName(tagName);
                    if (tag != null)
                    {
                        if (!feedback.Tags.Contains(tag))
                        {
                            feedback.Tags.Add(tag);
                        }
                    }
                    else
                    {
                        tag = new Tag
                        {
                            Name = tagName
                        };
                        tagService.Insert(tag);
                        feedback.Tags.Add(tag);
                    }
                }

                feedbackService.Update(feedback);

                #endregion
            }

            var result = new
            {
                success = ModelState.IsValid,
                message = string.Join("\n", ModelState.SelectMany(s => s.Value.Errors).Select(e => e.ErrorMessage))
            };
            return Json(result);
        }

        [ApplicationAuthorize(Permissions = Rights.Delete + Modules.Conversation)]
        public ActionResult Delete(Guid? id)
        {
            string message = "Failed to delete.";

            if (id.HasValue)
            {
                var feedback = feedbackService.GetById(id);
                if (feedback != null && !feedback.IsDeleted && (feedback.Manager.Id == GlobalVariables.CurrentUser.Id || (!feedback.IsPrivate && feedback.Employee.Id == GlobalVariables.CurrentUser.Id)))
                {
                    // Delete feedback
                    feedback.IsDeleted = true;
                    feedbackService.Update(feedback);

                    // Delete feedback comments
                    foreach (var comment in feedback.Comments)
                    {
                        comment.IsDeleted = true;
                        commentService.Update(comment);
                    }

                    message = string.Empty;
                }
            }

            var result = new
            {
                success = string.IsNullOrEmpty(message),
                message = message,
                redirect = new UrlHelper(Request.RequestContext).Action("Index", "Feedback", new { id = GlobalVariables.SelectedUser.Id })
            };
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (userManager != null)
                {
                    userManager.Dispose();
                    userManager = null;
                }                
            }

            base.Dispose(disposing);
        }
    }
}